#include "Game.h"

#include "SGD Wrappers/CSGD_Direct3D.h"
#include "SGD Wrappers/CSGD_DirectInput.h"
#include "SGD Wrappers/CSGD_TextureManager.h"
#include "SGD Wrappers/CSGD_XAudio2.h"

// States
#include "GamePlayState.h"
#include "MainMenuState.h"
#include "OptionsState.h"
#include "TutorialState.h"
#include "CreditsState.h"
#include "LoadGameState.h"
#include "UpgradeState.h"

#include "PickUp.h"


#include <time.h>
#include "tinyxml.h"

#include "resource.h"


void Game::Update(void)
{
	// Refresh the XAudio2
	m_pXA->Update();

	// Calculate the elapsed time
	DWORD now = GetTickCount();
	float elapsed = (now - gameTime) / 1000.0f;
	gameTime = now;

	if(elapsed > 0.125f)
		elapsed = 0.125f;

	// Let Current State Handle Update
	curState->Update(elapsed);

	if(hWnd != GetFocus() && GamePlayState::GetInstance()->inCutscene == false)
		GamePlayState::GetInstance()->SetPause(true);
}

void Game::Render(void)
{
	// Clear the background
	m_pD3D->Clear( 0, 0, 0 );

	// Start D3D rendering
	m_pD3D->DeviceBegin();
	m_pD3D->SpriteBegin();

	// Let the current state render
	curState->Render();

	m_pD3D->SpriteEnd();
	m_pD3D->DeviceEnd();

	m_pD3D->Present();
}

bool Game::Input(void)
{
	// Refresh the Direct Input buffers
	m_pDI->ReadDevices();

	return curState->Input();
}

void Game::ChangeState(IGameState* state)
{
	if( curState != nullptr )
		curState->Exit();

	curState = state;

	if( curState != nullptr )
		curState->Enter();
}

void Game::Init(HWND hwnd, HINSTANCE hinstance, int width, int height)
{
	// Random seed
	srand((unsigned int)time(0));

	hWnd = hwnd;

	// Access all the SGD Wrappers
	m_pD3D	= CSGD_Direct3D::GetInstance();
	m_pDI	= CSGD_DirectInput::GetInstance();
	m_pTM	= CSGD_TextureManager::GetInstance();
	m_pXA	= CSGD_XAudio2::GetInstance();

	// Initialize the wrappers
	m_pD3D->InitDirect3D( hwnd, width, height, notFullscreen, false);
	m_pDI->InitDirectInput( hwnd, hinstance, DI_KEYBOARD | DI_JOYSTICKS);
	m_pTM->InitTextureManager( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->InitXAudio2( );

	screenWidth = width;
	screenHeight = height;


	menuCursorID = m_pTM->LoadTexture(_T("Graphics/Menu Images/options_menu_stuffUPDATE.png"));

	// Menu Sounds
	menuMove	= m_pXA->SFXLoadSound(_T("Sound/Menu Sounds/menu_move.wav"));
	menuSelect	= m_pXA->SFXLoadSound(_T("Sound/Menu Sounds/menu_select.wav"));
	menuBack	= m_pXA->SFXLoadSound(_T("Sound/Menu Sounds/menu_back.wav"));
	menuMusic	= m_pXA->MusicLoadSong(_T("Sound/Music/menu_music.xwm"));

	// Getting group font
	GroupFont =	CBitmapFont::GetInstance();

	// Load resources
	FontImageID = CSGD_TextureManager::GetInstance()->LoadTexture(_T("Graphics/Robovox.bmp"), D3DCOLOR_XRGB(0,0,0));

	// Set the bitmap font's values
	GroupFont->SetValues(32, 32, 16, 14, ' ', FontImageID);

	// Attempt to load the sound
	if(LoadOptions("OptionsData.xml") == false)
	{
		CSGD_XAudio2::GetInstance()->MusicSetMasterVolume(1.0f);
		CSGD_XAudio2::GetInstance()->SFXSetMasterVolume(1.0f);

		notFullscreen = true;
		english = true;
	}

	LoadStrings(hinstance);

	ChangeState( MainMenuState::GetInstance() );

}

bool Game::Main(void)
{
	// Sanity-check
	if(curState == nullptr)
		return false;

	if(Input() == false)
		return false;

	Update();
	Render();

	return true;
}

void Game::Shutdown(void)
{
	ChangeState(NULL);

	// Unload resource
	if(FontImageID != -1)
	{
		CSGD_TextureManager::GetInstance()->UnloadTexture(FontImageID);
		FontImageID = -1;
	}

	if(menuCursorID != -1)
	{
		m_pTM->UnloadTexture(menuCursorID);
		menuCursorID = -1;
	}
		// Get rid of sounds here so other menus can use them
	if(menuMove != -1)
	{
		m_pXA->SFXStopSound(menuMove);
		m_pXA->SFXUnloadSound(menuMove);
		menuMove = -1;
	}
	if(menuSelect != -1)
	{
		m_pXA->SFXStopSound(menuSelect);
		m_pXA->SFXUnloadSound(menuSelect);
		menuSelect = -1;
	}
	if(menuBack != -1)
	{
		m_pXA->SFXStopSound(menuBack);
		m_pXA->SFXUnloadSound(menuBack);
		menuBack = -1;
	}
	if(menuMusic != -1)
	{
		m_pXA->MusicStopSong(menuMusic);
		m_pXA->MusicUnloadSong(menuMusic);
		menuMusic = -1;
	}

	if( m_pXA != nullptr )
	{
		m_pXA->ShutdownXAudio2();
		m_pXA = nullptr;
	}

	if( m_pTM != nullptr )
	{
		m_pTM->ShutdownTextureManager();
		m_pTM = nullptr;
	}

	if( m_pDI != nullptr )
	{
		m_pDI->ShutdownDirectInput();
		m_pDI = nullptr;
	}

	if( m_pD3D != nullptr )
	{
		m_pD3D->ShutdownDirect3D();
		m_pD3D = nullptr;
	}


	// full screen turned off
	notFullscreen = true;
	playMenuMusic = false;
}

Game::Game() 
{ 
	// full screen turned off
	notFullscreen = true;
	english = true;

	FontImageID = -1;
	GroupFont = nullptr;

	// Sounds
	menuMove	= -1;
	menuSelect	= -1;
	menuBack	= -1;
	menuMusic	= -1;
	playMenuMusic = true;
}

Game::~Game() { }

Game* Game::GetInstance(void)
{
	static Game instance;
	return &instance;
}

bool Game::LoadOptions(const char* szFileName)
{
	// Create a TinyXML Document
	TiXmlDocument doc;
	
	// Attempt to load the document from the file
	if(doc.LoadFile(szFileName) == false)
		return false;

	// Access the root node (sound_info) in the document
	TiXmlElement* pRoot = doc.RootElement();
	if(pRoot == nullptr)
		return false;

	// Clear out any existing sound data
	musicVolume = -1;
	sfxVolume = -1;

	// Iterate through the root's children nodes (sound_info)
	TiXmlElement* pOptions = pRoot->FirstChildElement("sound_info");


	// Read the attributes within the XML tag
	if(pOptions->Attribute("music",&musicVolume) != nullptr)
		CSGD_XAudio2::GetInstance()->MusicSetMasterVolume(musicVolume/100.0f);//MusicGetMasterVolume()*100.0f);
	if(pOptions->Attribute("sfx",&sfxVolume) != nullptr)
		CSGD_XAudio2::GetInstance()->SFXSetMasterVolume(sfxVolume/100.f);//SFXGetMasterVolume()*100.0f);

	float s = CSGD_XAudio2::GetInstance()->SFXGetMasterVolume();
	float m = CSGD_XAudio2::GetInstance()->MusicGetMasterVolume();
	// Move to the next node in the player_list
	pOptions = pOptions->NextSiblingElement("screen");

	int fs;
	// Read the attributes within the XML tag
	if(pOptions->Attribute("fullscreen",&fs) != nullptr)
	{
		if(fs == 0)
			SetFullScreen(true);
		else
		{
			SetFullScreen(false);
			m_pD3D->ChangeDisplayParam(screenWidth,screenHeight,notFullscreen);
		}
	}
	// Move to the next node in the player_list
	pOptions = pOptions->NextSiblingElement("language");

	int lan;
	if(pOptions->Attribute("english",&lan) != nullptr)
	{
		if(lan == 1)
			SetLanguage(true);
		else
			SetLanguage(false);
	}


	return true;
}

void Game::LoadStrings(HINSTANCE hI)
{
	// Main Menu
	MainMenuState* mm = MainMenuState::GetInstance();
	LoadString(hI,Dutch_MM_Play,	mm->playStr,	32);
	LoadString(hI,Dutch_MM_Options, mm->optionsStr,	32);
	LoadString(hI,Dutch_MM_HtP,		mm->htpStr,		32);
	LoadString(hI,Dutch_MM_Credits, mm->creditsStr,	32);
	LoadString(hI,Dutch_MM_Quit,	mm->quitStr,	32);

	// Options Menu
	OptionsState* om = OptionsState::GetInstance();
	LoadString(hI,Dutch_MM_Options,		om->optionStr,	 32);
	LoadString(hI,Dutch_OM_Sound,		om->soundStr,	 32);
	LoadString(hI,Dutch_OM_Music,		om->musicStr,	 32);
	LoadString(hI,Dutch_OM_Full,		om->fullStr,	 32);
	LoadString(hI,Dutch_OM_Language,	om->languageStr, 32);
	LoadString(hI,Dutch_OM_Back,		om->backStr,	 32);

	// Load Game
	LoadGameState* lg = LoadGameState::GetInstance();
	LoadString(hI,Dutch_LG_Load,		lg->loadStr,	32);
	LoadString(hI,Dutch_LG_Profile1,	lg->pro1Str,	32);
	LoadString(hI,Dutch_LG_Profile2,	lg->pro2Str,	32);
	LoadString(hI,Dutch_LG_Profile3,	lg->pro3Str,	32);
	LoadString(hI,Dutch_OM_Back,		lg->backStr,	32);
	LoadString(hI,Dutch_LG_Players,		lg->playersStr, 32);

	// GamePlay
	GamePlayState* gm = GamePlayState::GetInstance();
	LoadString(hI,Dutch_PG_Paused,		gm->pauseStr,	32);
	LoadString(hI,Dutch_PG_Resume,		gm->resumeStr,	32);
	LoadString(hI,Dutch_MM_Options,		gm->optionStr,	32);
	LoadString(hI,Dutch_PG_QuitGame,	gm->quitStr,	32);
	LoadString(hI,Dutch_GM_Metal,		gm->metalStr,	32);
	LoadString(hI,Dutch_GM_Circuitry,	gm->circuitStr,	32);

	// Upgrade Menu
	UpgradeState* up = UpgradeState::GetInstance();
	LoadString(hI,Dutch_GM_Circuitry,	up->circuitStr,		100);
	LoadString(hI,Dutch_UP_Scrap,		up->metalStr,		100);
	LoadString(hI,Dutch_UP_CurEquip,	up->curEqStr,		100);
	LoadString(hI,Dutch_UP_Melee,		up->meleeStr,		100);
	LoadString(hI,Dutch_UP_Ranged,		up->rangedStr,		100);
	LoadString(hI,Dutch_UP_Skills,		up->skillsStr,		100);
	LoadString(hI,Dutch_UP_Equip,		up->equipStr,		100);
	LoadString(hI,Dutch_UP_Exit,		up->exitStr,		100);
	LoadString(hI,Dutch_UP_Purchase,	up->purchaseStr,	100);
	LoadString(hI,Dutch_UP_Assign,		up->assignStr,		100);

	/* Descriptions */
	// Dutch
	LoadString(hI,Dutch_UP_Fist,		up->nlFistStr,	 200);	
	LoadString(hI,Dutch_UP_Sword,		up->nlSwordStr,	 200);
	LoadString(hI,Dutch_UP_Saw,			up->nlSawStr,	 200);
	LoadString(hI,Dutch_UP_Claw,		up->nlClawStr,	 200);
	LoadString(hI,Dutch_UP_Gun,			up->nlGunStr,	 200);
	LoadString(hI,Dutch_UP_Rocket,		up->nlRockStr,	 200);
	LoadString(hI,Dutch_UP_EMP,			up->nlEMPStr,	 225);
	LoadString(hI,Dutch_UP_Flame,		up->nlFlameStr,	 230);
	LoadString(hI,Dutch_UP_Camo,		up->nlCamoStr,	 200);
	LoadString(hI,Dutch_UP_Clock,		up->nlClockStr,	 200);
	LoadString(hI,Dutch_UP_Shield,		up->nlShieldStr, 200);
	LoadString(hI,Dutch_UP_Attr,		up->nlAttrStr,	 200);
	// English							
	LoadString(hI,English_UP_Fist,		up->enFistStr,	 175);
	LoadString(hI,English_UP_Sword,		up->enSwordStr,	 175);
	LoadString(hI,English_UP_Saw,		up->enSawStr,	 175);
	LoadString(hI,English_UP_Claw,		up->enClawStr,	 180);
	LoadString(hI,English_UP_Gun,		up->enGunStr,	 175);
	LoadString(hI,English_UP_Rocket,	up->enRockStr,	 175);
	LoadString(hI,English_UP_EMP,		up->enEMPStr,	 210);
	LoadString(hI,English_UP_Flame,		up->enFlameStr,	 225);
	LoadString(hI,English_UP_Camo,		up->enCamoStr,	 175);
	LoadString(hI,English_UP_Clock,		up->enClockStr,	 175);
	LoadString(hI,English_UP_Shield,	up->enShieldStr, 175);
	LoadString(hI,English_UP_Attr,		up->enAttrStr,	 175);

}

void Game::SaveGame(int slot, bool deletion)
{
	char file[100];
	sprintf_s(file,"Slot%i.xml", slot);


	// Create a TinyXML Document
	TiXmlDocument doc;

	// Create a TinyXML Declaration (version info)
	TiXmlDeclaration* pDec = new TiXmlDeclaration("1.0","utf-8","");
	// Add the declaration to the document
	doc.LinkEndChild(pDec);

	char save[100];
	sprintf_s(save,"SavedGame-Slot%i", slot);
	
	// Create a root node for the document (sound_list)
	TiXmlElement* pRoot = new TiXmlElement(save);
	// Add the root node to the document
	doc.LinkEndChild(pRoot);


	if(deletion == false)
	{
		// Create a node num of players
		TiXmlElement* pNumPlayers = new TiXmlElement("NumberofPlayers");
		// Fill the node with num info
		if(GamePlayState::GetInstance()->twoPlayer == false)
			pNumPlayers->SetAttribute("num",1);
		else
			pNumPlayers->SetAttribute("num",2);
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumPlayers);

		// Create a node num of savior pieces
		TiXmlElement* pNumPieces = new TiXmlElement("NumberofSAVIORPieces");
		// Fill the node with num info
		pNumPieces->SetAttribute("num",GamePlayState::GetInstance()->GetCurDungeon());
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumPieces);

		// Create a node for the weapons purchases
		TiXmlElement* pWeapons = new TiXmlElement("WeaponsPurchased");
		// Fill the node with the weapons info
		for(int i = 0; i < 10; i++)
		{
			char weapons[15];
			sprintf_s(weapons,"weapon%i", i+3);
			pWeapons->SetAttribute(weapons,GamePlayState::GetInstance()->GetPlayer()->purchased[i]);
		}
		// Add the weapons node to the saved game
		pRoot->LinkEndChild(pWeapons);

		// Create a node num of metal & circuitry
		TiXmlElement* pNumStuff = new TiXmlElement("NumberofMetalCircuitry");
		// Fill the node with num info
		pNumStuff->SetAttribute("numCircuitry",GamePlayState::GetInstance()->GetPlayer()->GetCircuitry());
		pNumStuff->SetAttribute("numMetal",GamePlayState::GetInstance()->GetPlayer()->GetMetal());
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumStuff);

		if(GamePlayState::GetInstance()->twoPlayer == true)
		{
			// Create a node for the weapons purchases for player 2
			TiXmlElement* pWeaponsP2 = new TiXmlElement("WeaponsPurchased-Player2");
			// Fill the node with the weapons info
			for(int i = 0; i < 10; i++)
			{
				char weapons[15];
				sprintf_s(weapons,"weapon%i", i+3);
				pWeaponsP2->SetAttribute(weapons,GamePlayState::GetInstance()->GetPlayer2()->purchased[i]);
			}
			// Add the weapons node to the saved game
			pRoot->LinkEndChild(pWeaponsP2);

			// Create a node num of metal & circuitry
			TiXmlElement* pNumStuffP2 = new TiXmlElement("NumberofMetalCircuitry-Player2");
			// Fill the node with num info
			pNumStuffP2->SetAttribute("numCircuitry",GamePlayState::GetInstance()->GetPlayer2()->GetCircuitry());
			pNumStuffP2->SetAttribute("numMetal",GamePlayState::GetInstance()->GetPlayer2()->GetMetal());
			// Add the num node to the saved game
			pRoot->LinkEndChild(pNumStuffP2);
		}
	}
	else
	{
				// Create a node num of players
		TiXmlElement* pNumPlayers = new TiXmlElement("NumberofPlayers");
		// Fill the node with num info
			pNumPlayers->SetAttribute("num",0);
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumPlayers);

		// Create a node num of savior pieces
		TiXmlElement* pNumPieces = new TiXmlElement("NumberofSAVIORPieces");
		// Fill the node with num info
		pNumPieces->SetAttribute("num",0);
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumPieces);

		// Create a node for the weapons purchases
		TiXmlElement* pWeapons = new TiXmlElement("WeaponsPurchased");
		// Fill the node with the weapons info
		for(int i = 0; i < 10; i++)
		{
			char weapons[15];
			sprintf_s(weapons,"weapon%i", i+3);
			pWeapons->SetAttribute(weapons,0);
		}
		// Add the weapons node to the saved game
		pRoot->LinkEndChild(pWeapons);

		// Create a node num of metal & circuitry
		TiXmlElement* pNumStuff = new TiXmlElement("NumberofMetalCircuitry");
		// Fill the node with num info
		pNumStuff->SetAttribute("numCircuitry",0);
		pNumStuff->SetAttribute("numMetal",0);
		// Add the num node to the saved game
		pRoot->LinkEndChild(pNumStuff);
	}


	// Save the XML document to the file
	doc.SaveFile(file);
}

bool Game::LoadGame(const char* szFileName, int slot)
{
	// Create a TinyXML Document

	TiXmlDocument doc;
	
	// Attempt to load the document from the file
	if(doc.LoadFile(szFileName) == false)
		return false;

	// Access the root node (sound_info) in the document
	TiXmlElement* pRoot = doc.RootElement();
	if(pRoot == nullptr)
		return false;



	pRoot = pRoot->FirstChildElement("NumberofPlayers");
	pRoot->Attribute("num", &LoadGameState::GetInstance()->saves[slot].numPlayers);
	int numPlayers =  LoadGameState::GetInstance()->saves[slot].numPlayers;
	pRoot = pRoot->NextSiblingElement("NumberofSAVIORPieces");

	pRoot->Attribute("num", &LoadGameState::GetInstance()->saves[slot].numPieces);
	pRoot = pRoot->NextSiblingElement("WeaponsPurchased");

	for(int i = 0; i < 10; i++)
	{
		char weapons[15];
		sprintf_s(weapons,"weapon%i", i+3);
		pRoot->Attribute(weapons, &LoadGameState::GetInstance()->saves[slot].purchased[i]);
	}
	pRoot = pRoot->NextSiblingElement("NumberofMetalCircuitry");

	pRoot->Attribute("numCircuitry", &LoadGameState::GetInstance()->saves[slot].numCircuitry);
	pRoot->Attribute("numMetal", &LoadGameState::GetInstance()->saves[slot].numMetal);

	if(numPlayers == 2)
	{
		pRoot = pRoot->NextSiblingElement("WeaponsPurchased-Player2");

		for(int i = 0; i < 10; i++)
		{
			char weapons[15];
			sprintf_s(weapons,"weapon%i", i+3);
			pRoot->Attribute(weapons, &LoadGameState::GetInstance()->saves[slot].purchasedP2[i]);
		}
		pRoot = pRoot->NextSiblingElement("NumberofMetalCircuitry-Player2");

		pRoot->Attribute("numCircuitry", &LoadGameState::GetInstance()->saves[slot].numCircuitryP2);
		pRoot->Attribute("numMetal", &LoadGameState::GetInstance()->saves[slot].numMetalP2);
	}





	//// Read the attributes within the XML tag
	//if(pOptions->Attribute("music",&musicVolume) == nullptr)
	//	musicVolume = (int)(CSGD_XAudio2::GetInstance()->MusicGetMasterVolume()*100.0f);
	//if(pOptions->Attribute("sfx",&sfxVolume) == nullptr)
	//	sfxVolume = (int)(CSGD_XAudio2::GetInstance()->SFXGetMasterVolume()*100.0f);
	//// Move to the next node in the player_list
	//pOptions = pOptions->NextSiblingElement("screen");






	return true;
}


